/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki.layers;

import android.graphics.Canvas;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;

import id.duapuluhdua.dakidaki.Command;
import id.duapuluhdua.dakidaki.MainDraw;
import id.duapuluhdua.dakidaki.R;
import id.duapuluhdua.dakidaki.common.CommonActivity;
import id.duapuluhdua.dakidaki.loader.TrackItem;
import id.duapuluhdua.dakidaki.map.GeoPoint;
import id.duapuluhdua.dakidaki.map.Screen;
import id.duapuluhdua.dakidaki.map.ScreenPoint;
import id.duapuluhdua.dakidaki.map.Viewport;

public class LayerTrack extends Layer
{
  /** Constants */
  private final static int POINT_RADIUS = 3;

  /** Fields */
  private Paint mPaintTrack;
  private Paint mPaintPoint;
  private Paint mPointLabel;

  private CornerPathEffect mPathEffectCorner = new CornerPathEffect(6);

  private Typeface mBold = Typeface.create((String)null, Typeface.BOLD);

  private Path mPath = new Path();

  private ScreenPoint mScreenPoint = new ScreenPoint();
  private ScreenPoint mScreenPointStart = new ScreenPoint();
  private ScreenPoint mScreenPointFinish = new ScreenPoint();

  private RectF mRtPoint;
  private Rect mRtLabelStart;
  private Rect mRtLabelFinish;

  private Boolean bResetViewPort = false;
  private Boolean bUpdateDrawPath = false;

  private String mLabelStart;
  private String mLabelFinish;
  private String mLabelLastPosition;

  private GeoPoint mPointStart;
  private GeoPoint mPointFinish;

  private TrackItem mTrackItem;

  /**
   *
   * @param parent
   * @param screen
   * @param trackItem
   */
  public LayerTrack(CommonActivity parent, Screen screen, TrackItem trackItem)
  {
	super(parent, screen);

	this.mTrackItem = trackItem;

	// Set the strings
	mLabelStart = parent.getString(R.string.label_track_point_start);
	mLabelFinish = parent.getString(R.string.label_track_point_finish);
	mLabelLastPosition = parent.getString(R.string.label_track_point_last_position);

  	// Track graphic properties
	mPaintTrack = new Paint();
	mPaintTrack.setAntiAlias(true);
	mPaintTrack.setARGB(255, 0, 0, 0);
	mPaintTrack.setStrokeWidth(4);
	mPaintTrack.setStyle(Paint.Style.STROKE);
	mPaintTrack.setStrokeCap(Paint.Cap.ROUND);
	mPaintTrack.setStrokeJoin(Paint.Join.ROUND);

  	// Point graphic properties
	mPaintPoint = new Paint();
	mPaintPoint.setAntiAlias(true);
	mPaintPoint.setColor(0xff000000);
	mPaintPoint.setStrokeWidth(1);
	mPaintPoint.setStyle(Paint.Style.FILL_AND_STROKE);
	mPaintPoint.setStrokeCap(Paint.Cap.ROUND);
	mPaintPoint.setStrokeJoin(Paint.Join.ROUND);

  	// Label graphic properties
	mPointLabel = new Paint();
	mPointLabel.setAntiAlias(true);
	mPointLabel.setTextSize(12);

	// Text bounds
	mPointLabel.getTextBounds(mLabelStart, 0, mLabelStart.length(), mRtLabelStart);
	mPointLabel.getTextBounds(mLabelFinish, 0, mLabelFinish.length(), mRtLabelFinish);

	mRtPoint = new RectF();
	mRtLabelStart = new Rect(0, 0, 0, 0);
	mRtLabelFinish = new Rect(0, 0, 0, 0);
  }

  @Override
  public void initData()
  {
    // Do nothing!
  }

  @Override
  public void surfaceSizeChanged(int width, int height, int screenOrientation)
  {
    // Do nothing!
  }

  public void setUpdateDrawPath()
  {
	synchronized(bUpdateDrawPath)
	{
	  bUpdateDrawPath = true;
	}
  }

  public void setResetViewPort()
  {
	synchronized(bResetViewPort)
	{
	  if (mParent.getMainState().allowObjectResetView()) {
		bResetViewPort = true;
	  }
	}
  }

  private void resetViewPort()
  {
	if (mTrackItem.isEmpty()) {
	  return;
	}

	synchronized(mTrackItem.vecTrackPoint)
	{
	  if (mTrackItem.isSelected()) {
		mScreen.resetViewport(mTrackItem.vecTrackPoint, Viewport.MODE_TRACKS);
	  }
	}
  }

  private void updateDrawPath()
  {
	if (mTrackItem.isEmpty()) {
	  return;
	}

	synchronized(mTrackItem.vecTrackPoint)
	{
	  synchronized(mPath)
	  {
		mPath.reset();
		for (int i = 0; i < mTrackItem.vecTrackPoint.size(); i++) {
		  mScreen.toScreenPoint(mTrackItem.vecTrackPoint.get(i), mScreenPoint);
		  if (i == 0) {
			mPath.moveTo(mScreenPoint.x, mScreenPoint.y);
		  }
		  else {
			mPath.lineTo(mScreenPoint.x, mScreenPoint.y);
		  }
		}
	  }

	  mPointStart = mTrackItem.vecTrackPoint.get(0);

	  mPointFinish = null;
      final int iPointsCount = mTrackItem.vecTrackPoint.size();
      if (iPointsCount > 1) {
		mPointFinish = mTrackItem.vecTrackPoint.get(iPointsCount - 1);
      }
	}
  }

  /**
   * Performs the drawing operation. At first, it checks whether the viewport
   * needs to be reset (i.e., recollect the geo-points). And it checks also
   * whether the path needs to be updated (i.e., redefine the path). Then,
   * the drawing process begins by picturing the track and the start-finish
   * point.
   *
   * @param canvas
   *          The drawing canvas object.
   * @param area
   *          The drawing area.
   */
  @Override
  public void doDraw(Canvas canvas, Rect area)
  {
    if (mState.getCurrentUiMode() == Command.CMD_MODE_TRACKS) {

      synchronized (bResetViewPort)
      {
        if (bResetViewPort) {
          bResetViewPort = false;
          resetViewPort();
        }
      }

      synchronized (bUpdateDrawPath)
      {
        if (bUpdateDrawPath) {
          bUpdateDrawPath = false;
          updateDrawPath();
        }
      }

      // Set the track color
      if (mTrackItem.isSelected()) {
        if (mTrackItem.isRecording()) {
          mPaintTrack.setColor(0xffff0000);
        }
        else {
          mPaintTrack.setColor(0xff888888);
        }
      }
      else {
        if (mTrackItem.isRecording()) {
          mPaintTrack.setColor(0xffff8888);
        }
        else {
          mPaintTrack.setColor(0xffcccccc);
        }
      }

      // Draw the track
      synchronized (mPath) {
        mPaintTrack.setPathEffect(mPathEffectCorner);
        MainDraw.compassRotation.set(canvas);
        canvas.drawPath(mPath, mPaintTrack);
        MainDraw.compassRotation.clear(canvas);
        mPaintTrack.setPathEffect(null);
      }

      // Draw the start and finish points
      drawLimitPoints(canvas);
    }
  }

  /**
   *
   * @param canvas
   */
  private void drawLimitPoints(Canvas canvas)
  {
	if (mTrackItem.isEmpty()) {
	  return;
	}

	mPointLabel.setTypeface(mBold);

	synchronized(mTrackItem.vecTrackPoint)
	{
	  // Draw the start point
  	  if (mPointStart != null) {
  	    mScreen.toScreenPoint(mPointStart, mScreenPointStart);
		drawPoint(canvas, mScreenPointStart, true, mLabelStart, mRtLabelStart);
  	  }

  	  // Draw the finish point
  	  if (mPointFinish != null) {
		mScreen.toScreenPoint(mPointFinish, mScreenPointFinish);

        if (mTrackItem.isClosed()) {
          drawPoint(canvas, mScreenPointFinish, false, mLabelFinish, mRtLabelFinish);
        }
        else {
          drawPoint(canvas, mScreenPointFinish, false, mLabelLastPosition, mRtLabelFinish);
        }
  	  }
	}
  }

  private void drawPoint(Canvas canvas, ScreenPoint coords, boolean bStartPoint,
      String sLabel, Rect rtLabel)
  {
	// Transform point with compass rotation
	MainDraw.compassRotation.transformPoint(coords);

	// Draw border
	mRtPoint.set(coords.x - POINT_RADIUS, coords.y - POINT_RADIUS,
	            coords.x + POINT_RADIUS, coords.y + POINT_RADIUS);

	mPaintPoint.setColor(0xff000000);
	canvas.drawOval(mRtPoint, mPaintPoint);

	// Fill inner
	mRtPoint.inset(2, 2);

	mPaintPoint.setColor(0xffcccccc);
	canvas.drawOval(mRtPoint, mPaintPoint);

	// Draw point label
	if (bStartPoint) {
	  mPointLabel.setColor(0xff442200);
	}
	else {
	  if (mTrackItem.isRecording()) {
		mPointLabel.setColor(0xffff4444);
	  }
	  else {
		mPointLabel.setColor(0xffff8800);
	  }
	}
	canvas.drawText(sLabel, coords.x+8, coords.y+rtLabel.height()+3, mPointLabel);
  }

  public void setResetViewport()
  {
    synchronized(bResetViewPort)
    {
      if (mParent.getMainState().allowObjectResetView()) {
        bResetViewPort = true;
      }
    }
  }

  @Override
  public void updateObjectsState()
  {
    // Do nothing!
  }
}
